﻿/*
COPYRIGHT (C) 2010-2011 Raynald Messié

THIS FILE IS PART OF SCRUMPILOT.

SCRUMPILOT IS FREE SOFTWARE: YOU CAN REDISTRIBUTE IT AND/OR MODIFY IT UNDER THE TERMS OF 
THE GNU LESSER GENERAL PUBLIC LICENSE VERSION v2.1 AS PUBLISHED BY THE FREE SOFTWARE FOUNDATION.

SCRUMPILOT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY WARRANTY; WITHOUT
EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. SEE THE GNU LESSER
GENERAL PUBLIC LICENSE FOR MORE DETAILS.

YOU SHOULD HAVE RECEIVED A COPY OF THE GNU LESSER GENERAL PUBLIC LICENSE ALONG WITH SCRUMPILOT. 
IF NOT, SEE <HTTP://WWW.GNU.ORG/LICENSES/>.
*/

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.WorkItemTracking.Client;

namespace ScrumPilot.TFSHelpers
{
    public partial class TFSServices
    {
        private List<Identity> _lstAlluser;

        protected List<Identity> LstAlluser
        {
            get { return _lstAlluser ?? (_lstAlluser = GetAllTfsUsers()); }
        }

        #region User & Identity

        /// <summary>
        /// Get the users list of a project
        /// </summary>
        /// <returns>User List</returns>
        //public Dictionary<string, user> GetProjectContributorsLookup(string tfsProject)
        //{
        //    var contributors = new Dictionary<string, user>();
        //    string groupName = string.Format(@"[{0}]\Contributors", tfsProject);
        //    Identity contributorsGroup = TfsGroupSecurityService.ReadIdentity(SearchFactor.AccountName, groupName,
        //                                                                           QueryMembership.Expanded);

        //    if (contributorsGroup == null)
        //    {
        //        throw new Exception("Could not read group: " + groupName);
        //    }
        //    if (contributorsGroup.Members == null)
        //    {
        //        throw new Exception("Members of group " + groupName + " is NULL");
        //    }
        //    foreach (string memberSid in contributorsGroup.Members)
        //    {
        //        Identity memberInfo = TfsGroupSecurityService.ReadIdentity(SearchFactor.Sid, memberSid, 0);
        //        if (((memberInfo.Type == IdentityType.WindowsUser) && !memberInfo.Deleted) &&
        //            !contributors.ContainsKey(memberInfo.DisplayName))
        //        {
        //            contributors.Add(memberInfo.DisplayName,
        //                             new user
        //                                 {
        //                                     name = memberInfo.DisplayName,
        //                                     tfsuserid = memberInfo.Sid,
        //                                     deleted = memberInfo.Deleted
        //                                 });
        //        }
        //    }

        //    return contributors;
        //}

        /// <summary>
        /// Get all Role Tfs Users in a Project 
        /// </summary>
        /// <param name="projectName">Project name</param>
        /// <returns>A list of identity</returns>
        public List<Identity> GetTfsUsersInProject(String projectName)
        {
            var lstRet = new List<Identity>();
            Identity[] appGroups = TfsGroupSecurityService.ListApplicationGroups(
                    TfsVersionControlServer.GetTeamProject(projectName).ArtifactUri.AbsoluteUri);

            foreach (Identity group in appGroups)
            {
                Identity[] groupMembers = TfsGroupSecurityService.ReadIdentities(SearchFactor.Sid,
                                                                                      new[] { group.Sid },
                                                                                      QueryMembership.Expanded);
                foreach (Identity member in groupMembers)
                {
                    foreach (string memberSid in member.Members)
                    {
                        Identity memberInfo = TfsGroupSecurityService.ReadIdentity(SearchFactor.Sid, memberSid, QueryMembership.None);

                        if (memberInfo.Type == IdentityType.WindowsUser && !memberInfo.Deleted  && !lstRet.Contains(memberInfo))
                            lstRet.Add(memberInfo);
                    }
                }
            }
            return (lstRet);
        }

        public List<TFSResumeProjectForUser> GetProjectsUseBy(String sid)
        {
            var lstRet = new ConcurrentBag<TFSResumeProjectForUser>();
            ProjectCollection projects = TfsWorkItemStore.Projects;
            foreach (Project project in projects)
            {
                Identity[] appGroups =
                    TfsGroupSecurityService.ListApplicationGroups(
                        TfsVersionControlServer.GetTeamProject(project.Name).ArtifactUri.AbsoluteUri);
                Parallel.ForEach(appGroups, group =>
                                                          {
                                                              Identity[] groupMembers =
                                                                  TfsGroupSecurityService.ReadIdentities(
                                                                      SearchFactor.Sid, new[] { group.Sid },
                                                                      QueryMembership.Expanded);
                                                              foreach (Identity member in groupMembers)
                                                              {
                                                                  if (member.Members.Contains(sid))
                                                                  {
                                                                      var c = lstRet.FirstOrDefault(p => p.ID == project.Id);
                                                                      if (c == null)
                                                                      {
                                                                          c = new TFSResumeProjectForUser
                                                                                   {
                                                                                       ID = project.Id,
                                                                                       Name = project.Name,
                                                                                       Roles = new List<ProjectRoles>()
                                                                                   };
                                                                          c.Roles.Add(new ProjectRoles
                                                                                          {
                                                                                              SID = member.Sid,
                                                                                              DisplayName = member.DisplayName,
                                                                                              Description = member.Description
                                                                                          });
                                                                          lstRet.Add(c);
                                                                      }
                                                                      else
                                                                      {
                                                                          if (!c.Roles.Exists(p => p.SID == member.Sid))
                                                                          {
                                                                              c.Roles.Add(new ProjectRoles
                                                                                              {
                                                                                                  SID = member.Sid,
                                                                                                  DisplayName = member.DisplayName,
                                                                                                  Description = member.Description
                                                                                              });
                                                                          }
                                                                      }
                                                                  }
                                                              }
                                                          });
            }

            return lstRet.OrderBy(p => p.Name).ToList();
        }

        /// <summary>
        /// Get all users in all project
        /// </summary>
        /// <returns>List of users</returns>
        public List<Identity> GetAllTfsUsers()
        {
            var lstRet = new List<Identity>();
            var projects = GetProjects();
            foreach (string project in projects)
            {
                (GetTfsUsersInProject(project)).ForEach(delegate(Identity ide)
                                                                 {
                                                                     if (!lstRet.Contains(ide))
                                                                         lstRet.Add(ide);
                                                                 });
            }
            return (lstRet);
        }

        /// <summary>
        /// Get the TFS identity
        /// </summary>
        /// <param name="search"></param>
        /// <param name="sf">Search factor</param>
        /// <returns>TFS identity</returns>
        public Identity GetTFSIndentity(String search, SearchFactor sf)
        {
            return TfsGroupSecurityService.ReadIdentity(sf, search, QueryMembership.Direct);
        }

        /// <summary>
        /// Get the TFS identity
        /// </summary>
        /// <param name="sid">Unique TFS userID</param>
        /// <returns>TFS identity</returns>
        public Identity GetTFSIndentity(String sid)
        {
            return GetTFSIndentity(sid, SearchFactor.Sid);
        }

        /// <summary>
        /// Get the TFS identity
        /// </summary>
        /// <param name="accountname">Account TFS name</param>
        /// <returns>TFS identity</returns>
        public Identity GetTFSIndentityByAccountName(String accountname)
        {
            return GetTFSIndentity(accountname, SearchFactor.AccountName);
        }

        /// <summary>
        /// Get the TFS SID
        /// => The "Assigned To" field in work item is the display name,
        /// and there is no SearchFactor on displayname
        /// </summary>
        /// <param name="username">The display name of user</param>
        /// <returns>Sid of user</returns>
        public String GetTFSIndentityByName(String username)
        {
            String sRet = null;
            if (LstAlluser.Count > 0)
            {
                Identity usr = LstAlluser.FirstOrDefault(p => p.DisplayName == username);
                if (usr != null)
                    sRet = usr.Sid;
            }
            return sRet;
        }

        /// <summary>
        /// Get the admin status of an identity (admin status => this user in in Project Collection Administrators Group)
        /// </summary>
        /// <param name="sID">Unique ID of user to check</param>
        /// <returns>True = is Admin</returns>
        public Boolean IsAdmin(String sID)
        {
            return this.IsAdmin(this.GetTFSIndentity(sID));
        }

        /// <summary>
        /// Get the admin status of an identity (admin status => this user in in Project Collection Administrators Group)
        /// </summary>
        /// <param name="identity">Identity to check</param>
        /// <returns>True = is Admin</returns>
        public Boolean IsAdmin(Identity identity)
        {
            const string groupName = @"Project Collection Administrators";
            //string groupName = string.Format(@"[{0}]\Project Collection Administrators", identity.Domain);
            Identity adminGroup = this.TfsGroupSecurityService.ReadIdentity(SearchFactor.AccountName, groupName,
                                                                            QueryMembership.Expanded);
            return adminGroup.Members.Contains(identity.Sid);
        }



        #endregion
    }

    public class TFSResumeProjectForUser
    {
        public Int32 ID { get; set; }
        public String Name { get; set; }
        public String Description { get; set; }
        public List<ProjectRoles> Roles { get; set; }
    }

    public class ProjectRoles
    {
        public String SID { get; set; }
        public String DisplayName { get; set; }
        public String Description { get; set; }
    }
}